import { useState, useCallback, useRef } from 'react';

/**
 * 视口状态接口
 */
export interface ViewportState {
  /** 缩放比例 */
  scale: number;
  /** X轴平移量 */
  translateX: number;
  /** Y轴平移量 */
  translateY: number;
}

/**
 * 视口管理Hook配置
 */
interface UseViewportOptions {
  /** 最小缩放比例 */
  minScale?: number;
  /** 最大缩放比例 */
  maxScale?: number;
  /** 缩放步长 */
  scaleStep?: number;
  /** 初始视口状态 */
  initialViewport?: Partial<ViewportState>;
}

/**
 * 视口管理Hook
 * 提供缩放、平移等视口变换功能，保持画布逻辑坐标系不变
 */
export const useViewport = (options: UseViewportOptions = {}) => {
  const { minScale = 0.1, maxScale = 3, scaleStep = 0.1, initialViewport = {} } = options;

  // 视口状态
  const [viewport, setViewport] = useState<ViewportState>({
    scale: 1,
    translateX: 0,
    translateY: 0,
    ...initialViewport,
  });

  // 拖拽状态
  const dragStateRef = useRef<{
    isDragging: boolean;
    startX: number;
    startY: number;
    startTranslateX: number;
    startTranslateY: number;
  }>({
    isDragging: false,
    startX: 0,
    startY: 0,
    startTranslateX: 0,
    startTranslateY: 0,
  });

  /**
   * 限制缩放比例在有效范围内
   */
  const clampScale = useCallback(
    (scale: number) => {
      return Math.max(minScale, Math.min(maxScale, scale));
    },
    [minScale, maxScale]
  );

  /**
   * 放大视口
   */
  const zoomIn = useCallback(() => {
    setViewport(prev => ({
      ...prev,
      scale: clampScale(prev.scale + scaleStep),
    }));
  }, [clampScale, scaleStep]);

  /**
   * 缩小视口
   */
  const zoomOut = useCallback(() => {
    setViewport(prev => ({
      ...prev,
      scale: clampScale(prev.scale - scaleStep),
    }));
  }, [clampScale, scaleStep]);

  /**
   * 缩放到指定比例
   * @param scale 目标缩放比例
   * @param centerX 缩放中心X坐标（相对于容器）
   * @param centerY 缩放中心Y坐标（相对于容器）
   */
  const zoomToScale = useCallback(
    (scale: number, centerX?: number, centerY?: number) => {
      setViewport(prev => {
        const newScale = clampScale(scale);

        // 如果提供了缩放中心点，计算平移偏移以保持中心点位置
        if (centerX !== undefined && centerY !== undefined) {
          const scaleDiff = newScale - prev.scale;
          const newTranslateX = prev.translateX - centerX * scaleDiff;
          const newTranslateY = prev.translateY - centerY * scaleDiff;

          return {
            scale: newScale,
            translateX: newTranslateX,
            translateY: newTranslateY,
          };
        }

        return {
          ...prev,
          scale: newScale,
        };
      });
    },
    [clampScale]
  );

  /**
   * 平移视口
   * @param deltaX X轴平移量
   * @param deltaY Y轴平移量
   */
  const pan = useCallback((deltaX: number, deltaY: number) => {
    setViewport(prev => ({
      ...prev,
      translateX: prev.translateX + deltaX,
      translateY: prev.translateY + deltaY,
    }));
  }, []);

  /**
   * 重置视口到初始状态
   */
  const reset = useCallback(() => {
    setViewport({
      scale: 1,
      translateX: 0,
      translateY: 0,
      ...initialViewport,
    });
  }, [initialViewport]);

  /**
   * 适应指定尺寸
   * @param containerWidth 容器宽度
   * @param containerHeight 容器高度
   * @param contentWidth 内容宽度
   * @param contentHeight 内容高度
   * @param padding 边距
   */
  const fitToSize = useCallback(
    (
      containerWidth: number,
      containerHeight: number,
      contentWidth: number,
      contentHeight: number,
      padding: number = 40
    ) => {
      const availableWidth = containerWidth - padding * 2;
      const availableHeight = containerHeight - padding * 2;

      const scaleX = availableWidth / contentWidth;
      const scaleY = availableHeight / contentHeight;
      const fitScale = clampScale(Math.min(scaleX, scaleY));

      const scaledWidth = contentWidth * fitScale;
      const scaledHeight = contentHeight * fitScale;

      const translateX = (containerWidth - scaledWidth) / 2;
      const translateY = (containerHeight - scaledHeight) / 2;

      setViewport({
        scale: fitScale,
        translateX,
        translateY,
      });
    },
    [clampScale]
  );

  /**
   * 处理滚轮缩放
   * @param event 滚轮事件
   * @param containerRect 容器边界矩形
   */
  const handleWheel = useCallback(
    (event: WheelEvent, containerRect: DOMRect) => {
      // 只有按住Ctrl或Cmd键时才进行缩放
      if (!event.ctrlKey && !event.metaKey) return;

      event.preventDefault();

      const centerX = event.clientX - containerRect.left;
      const centerY = event.clientY - containerRect.top;
      const delta = event.deltaY > 0 ? -scaleStep : scaleStep;

      setViewport(prev => {
        const newScale = clampScale(prev.scale + delta);
        const scaleDiff = newScale - prev.scale;
        const newTranslateX = prev.translateX - centerX * scaleDiff;
        const newTranslateY = prev.translateY - centerY * scaleDiff;

        return {
          scale: newScale,
          translateX: newTranslateX,
          translateY: newTranslateY,
        };
      });
    },
    [clampScale, scaleStep]
  );

  /**
   * 开始拖拽
   * @param clientX 鼠标X坐标
   * @param clientY 鼠标Y坐标
   */
  const startDrag = useCallback(
    (clientX: number, clientY: number) => {
      dragStateRef.current = {
        isDragging: true,
        startX: clientX,
        startY: clientY,
        startTranslateX: viewport.translateX,
        startTranslateY: viewport.translateY,
      };
    },
    [viewport.translateX, viewport.translateY]
  );

  /**
   * 拖拽中
   * @param clientX 鼠标X坐标
   * @param clientY 鼠标Y坐标
   */
  const drag = useCallback((clientX: number, clientY: number) => {
    const dragState = dragStateRef.current;
    if (!dragState.isDragging) return;

    const deltaX = clientX - dragState.startX;
    const deltaY = clientY - dragState.startY;

    setViewport(prev => ({
      ...prev,
      translateX: dragState.startTranslateX + deltaX,
      translateY: dragState.startTranslateY + deltaY,
    }));
  }, []);

  /**
   * 结束拖拽
   */
  const endDrag = useCallback(() => {
    dragStateRef.current.isDragging = false;
  }, []);

  /**
   * 屏幕坐标转换为画布坐标
   * @param screenX 屏幕X坐标
   * @param screenY 屏幕Y坐标
   * @returns 画布坐标
   */
  const screenToCanvas = useCallback(
    (screenX: number, screenY: number) => {
      return {
        x: (screenX - viewport.translateX) / viewport.scale,
        y: (screenY - viewport.translateY) / viewport.scale,
      };
    },
    [viewport]
  );

  /**
   * 画布坐标转换为屏幕坐标
   * @param canvasX 画布X坐标
   * @param canvasY 画布Y坐标
   * @returns 屏幕坐标
   */
  const canvasToScreen = useCallback(
    (canvasX: number, canvasY: number) => {
      return {
        x: canvasX * viewport.scale + viewport.translateX,
        y: canvasY * viewport.scale + viewport.translateY,
      };
    },
    [viewport]
  );

  return {
    viewport,
    zoomIn,
    zoomOut,
    zoomToScale,
    pan,
    reset,
    fitToSize,
    handleWheel,
    startDrag,
    drag,
    endDrag,
    screenToCanvas,
    canvasToScreen,
    // 状态查询
    canZoomIn: viewport.scale < maxScale,
    canZoomOut: viewport.scale > minScale,
    isDragging: dragStateRef.current.isDragging,
  };
};
